package com.ruge.common.jpa;

import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.util.*;

/**
 * 创建人 ：爱丽丝、如歌
 * 创建时间 ：2020-03-05  20:34
 * 描述 ：
 *
 * @author Administrator
 */
@SuppressWarnings("SpringJavaConstructorAutowiringInspection")
@Transactional(rollbackFor = Exception.class)
public class BaseRepositoryImpl<T, ID extends Serializable>
        extends SimpleJpaRepository<T, ID>
        implements BaseRepository<T, ID> {

    private static final int BATCH_SIZE = 500;

    private final JpaEntityInformation<T, ?> entityInformation;
    private final EntityManager em;

    public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityInformation = entityInformation;
        this.em = entityManager;
    }

    public BaseRepositoryImpl(Class<T> domainClass, JpaEntityInformation<T, ?> entityInformation, EntityManager em) {
        super(domainClass, em);
        this.entityInformation = entityInformation;
        this.em = em;
    }

    @Override
    public <S extends T> S save(S entity) {

        if (entityInformation.isNew(entity)) {
            em.persist(entity);
            return entity;
        } else {
            //获取空属性并处理成null
            String[] nullProperties = getNullProperties(entity);
            //获取ID
            ID entityId = (ID) entityInformation.getId(entity);
            //1.获取最新对象
            T target  =  findById(entityId).get();
            //2.将非空属性覆盖到最新对象
            BeanUtils.copyProperties(entity, target, nullProperties);
            em.merge(target);
            return entity;
        }
    }

    @Override
    public <S extends T> Iterable<S> batchSave(Iterable<S> var1) {
        Iterator<S> iterator = var1.iterator();
        int index = 0;
        while (iterator.hasNext()) {
            em.persist(iterator.next());
            index++;
            if (index % BATCH_SIZE == 0) {
                em.flush();
                em.clear();
            }
        }
        if (index % BATCH_SIZE != 0) {
            em.flush();
            em.clear();
        }
        return var1;
    }

    @Override
    public <S extends T> Iterable<S> batchUpdate(Iterable<S> var1) {
        Iterator<S> iterator = var1.iterator();
        int index = 0;
        while (iterator.hasNext()) {
            em.merge(iterator.next());
            index++;
            if (index % BATCH_SIZE == 0) {
                em.flush();
                em.clear();
            }
        }
        if (index % BATCH_SIZE != 0) {
            em.flush();
            em.clear();
        }
        return var1;
    }

    /**
     * 批量操作
     *
     * @param map
     * @return
     */
    @Override
    public List<T> batch(Map<String, List<T>> map) {
        List<T> result = null;
        if (map.containsKey("delete")) {
            result = map.get("delete");
            super.deleteInBatch(result);
        } else if (map.containsKey("update")) {
            result = map.get("update");
            batchUpdate(result);
        } else if (map.containsKey("create")) {
            result = map.get("create");
            batchSave(result);
        }
        return result;
    }


    /**
     * 基于原生态的sql进行查询
     *
     * @param sql
     * @return
     */
    @Override
    public List<Map<String, Object>> findAllBySql(String sql) {
        Query query = em.createNativeQuery(sql);
        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return query.getResultList();
    }

    /**
     * 基于Hibernate的HQL进行查询
     *
     * @param hql
     * @return
     */
    @Override
    public List<Map<String, Object>> findAllByHql(String hql) {
        Query query = em.createQuery(hql);
        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return query.getResultList();
    }

    /**
     * 获取对象的空属性
     */
    private static String[] getNullProperties(Object src) {
        //1.获取Bean
        BeanWrapper srcBean = new BeanWrapperImpl(src);
        //2.获取Bean的属性描述
        PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();
        //3.获取Bean的空属性
        Set<String> properties = new HashSet<>();
        for (PropertyDescriptor propertyDescriptor : pds) {
            String propertyName = propertyDescriptor.getName();
            Object propertyValue = srcBean.getPropertyValue(propertyName);
            if (StringUtils.isEmpty(propertyValue)) {
                srcBean.setPropertyValue(propertyName, null);
                properties.add(propertyName);
            }
        }
        return properties.toArray(new String[0]);
    }
}
